#define ZGRAPHICS_SOURCE
#include "SFMLContext.hpp"
#ifdef ZZZ_CONTEXT_SFML
#include "../Renderer/Renderer.hpp"
#include "../Graphics/OpenGLTools.hpp"

namespace zzz{
SFMLContext::SFMLContext(void)
:App_(NULL)
{
}

SFMLContext::~SFMLContext(void)
{
  if (App_) delete App_;
}

void SFMLContext::Initialize(Renderer* renderer, const string &title, int sizex, int sizey)
{
  SetRenderer(renderer);


  char windowtitle[1024]="zzzEngine in SFML";
  if (title) strcpy(windowtitle,title);
    App_=new sf::RenderWindow(sf::VideoMode(sizex, sizey), windowtitle);

#ifdef ZZZ_OPENGL_MX
  OpenGLMutex.Lock();
#endif // ZZZ_OPENGL_MX
  InitGLEW();
  MakeCurrent();
  renderer_->InitState();
  renderer_->InitData();
#ifdef ZZZ_OPENGL_MX
  OpenGLMutex.Unlock();
#endif // ZZZ_OPENGL_MX

  renderer_->OnSize(0, sizex, sizey);
  width_=sizex;
  height_=sizey;

    // Start game loop
    while (App_->IsOpened())
    {
        // Process events
        sf::Event Event;
        while (App_->GetEvent(Event))
        {
      switch(Event.Type)
      {
      case sf::Event::Closed:
        App_->Close();
        break;
      case sf::Event::KeyPressed:
        Context::OnKeyDown(SFMLKey2ZZZKey(Event.Key.Code),0
          ,(Event.Key.Alt?ZZZFLAG_ALT:0) | (Event.Key.Control?ZZZFLAG_CTRL:0) | (Event.Key.Shift?ZZZFLAG_SHIFT:0));
        break;
      case sf::Event::KeyReleased:
        Context::OnKeyUp(SFMLKey2ZZZKey(Event.Key.Code),0
          ,(Event.Key.Alt?ZZZFLAG_ALT:0) | (Event.Key.Control?ZZZFLAG_CTRL:0) | (Event.Key.Shift?ZZZFLAG_SHIFT:0));
        break;
      case sf::Event::Resized:
        Context::OnSize(0, Event.Size.Width, Event.Size.Height);
        width_=Event.Size.Width;
        height_=Event.Size.Height;
        break;
      case sf::Event::TextEntered:
        Context::OnChar(Event.Text.Unicode, 0, 0);
        break;
      case sf::Event::MouseMoved:
        Context::OnMouseMove(GetInputFlag(),Event.MouseMove.X,Event.MouseMove.Y);
        break;
      case sf::Event::MouseButtonPressed:
        if (Event.MouseButton.Button==sf::Mouse::Left)
          Context::OnLButtonDown(GetInputFlag(),Event.MouseButton.X,Event.MouseButton.Y);
        else if (Event.MouseButton.Button==sf::Mouse::Right)
          Context::OnRButtonDown(GetInputFlag(),Event.MouseButton.X,Event.MouseButton.Y);
        else if (Event.MouseButton.Button==sf::Mouse::Middle)
          Context::OnMButtonDown(GetInputFlag(),Event.MouseButton.X,Event.MouseButton.Y);
        break;
      case sf::Event::MouseButtonReleased:
        if (Event.MouseButton.Button==sf::Mouse::Left)
          Context::OnLButtonUp(GetInputFlag(),Event.MouseButton.X,Event.MouseButton.Y);
        else if (Event.MouseButton.Button==sf::Mouse::Right)
          Context::OnRButtonUp(GetInputFlag(),Event.MouseButton.X,Event.MouseButton.Y);
        else if (Event.MouseButton.Button==sf::Mouse::Middle)
          Context::OnMButtonUp(GetInputFlag(),Event.MouseButton.X,Event.MouseButton.Y);
        break;
      case sf::Event::MouseWheelMoved:
        renderer_->OnMouseWheel(GetInputFlag(),Event.MouseWheel.Delta,App_->GetInput().GetMouseX(),App_->GetInput().GetMouseX());
        break;
      //not support by zzzEngine yet
      case sf::Event::MouseEntered:
      case sf::Event::MouseLeft:
      case sf::Event::LostFocus:
      case sf::Event::GainedFocus:
      case sf::Event::JoyButtonPressed:
      case sf::Event::JoyButtonReleased:
      case sf::Event::JoyMoved:
        break;
      }
         }
    if (needRedraw_)
    {
      RenderScene();
      needRedraw_=false;
    }
    }

    // Don't forget to destroy our texture
//    glDeleteTextures(1, &Texture);}
}

void SFMLContext::Redraw()
{
  needRedraw_=true;
}

void SFMLContext::SwapBuffer()
{
  App_->Display();
}

void SFMLContext::MakeCurrent()
{
  App_->SetActive();
  Context::MakeCurrent();
}

unsigned int SFMLContext::SFMLKey2ZZZKey(sf::Key::Code &code)
{
  switch(code)
  {
  case sf::Key::A: return ZZZKEY_a;
  case sf::Key::B: return ZZZKEY_b;
    case sf::Key::C: return ZZZKEY_c;
    case sf::Key::D: return ZZZKEY_d;
    case sf::Key::E: return ZZZKEY_e;
    case sf::Key::F: return ZZZKEY_f;
    case sf::Key::G: return ZZZKEY_g;
    case sf::Key::H: return ZZZKEY_h;
    case sf::Key::I: return ZZZKEY_i;
    case sf::Key::J: return ZZZKEY_j;
    case sf::Key::K: return ZZZKEY_k;
    case sf::Key::L: return ZZZKEY_l;
    case sf::Key::M: return ZZZKEY_m;
    case sf::Key::N: return ZZZKEY_n;
    case sf::Key::O: return ZZZKEY_o;
    case sf::Key::P: return ZZZKEY_p;
    case sf::Key::Q: return ZZZKEY_q;
    case sf::Key::R: return ZZZKEY_r;
    case sf::Key::S: return ZZZKEY_s;
    case sf::Key::T: return ZZZKEY_t;
    case sf::Key::U: return ZZZKEY_u;
    case sf::Key::V: return ZZZKEY_v;
    case sf::Key::W: return ZZZKEY_w;
    case sf::Key::X: return ZZZKEY_x;
    case sf::Key::Y: return ZZZKEY_y;
    case sf::Key::Z: return ZZZKEY_z;
    case sf::Key::Num0: return ZZZKEY_NUM_0;
    case sf::Key::Num1: return ZZZKEY_NUM_1;
    case sf::Key::Num2: return ZZZKEY_NUM_2;
    case sf::Key::Num3: return ZZZKEY_NUM_3;
    case sf::Key::Num4: return ZZZKEY_NUM_4;
    case sf::Key::Num5: return ZZZKEY_NUM_5;
    case sf::Key::Num6: return ZZZKEY_NUM_6;
    case sf::Key::Num7: return ZZZKEY_NUM_7;
    case sf::Key::Num8: return ZZZKEY_NUM_8;
    case sf::Key::Num9: return ZZZKEY_NUM_9;
    case sf::Key::Escape: return ZZZKEY_ESC;
    case sf::Key::LControl: return ZZZKEY_LCTRL;
    case sf::Key::LShift: return ZZZKEY_LSHIFT;
    case sf::Key::LAlt: return ZZZKEY_LALT;
    case sf::Key::LSystem: return ZZZKEY_LMETA;
    case sf::Key::RControl: return ZZZKEY_RCTRL;
    case sf::Key::RShift: return ZZZKEY_RSHIFT;
    case sf::Key::RAlt: return ZZZKEY_RALT;
    case sf::Key::RSystem: return ZZZKEY_RMETA;
    case sf::Key::Menu: return ZZZKEY_MENU;
    case sf::Key::LBracket: return ZZZKEY_LSB;
    case sf::Key::RBracket: return ZZZKEY_RSB;
    case sf::Key::SemiColon: return ZZZKEY_SCOLON;
    case sf::Key::Comma: return ZZZKEY_COMMA;
    case sf::Key::Period: return ZZZKEY_DOT;
    case sf::Key::Quote: return ZZZKEY_SQM;
    case sf::Key::Slash: return ZZZKEY_SLASH;
    case sf::Key::BackSlash: return ZZZKEY_BSLASH;
    case sf::Key::Tilde: return ZZZKEY_TILDE;
    case sf::Key::Equal: return ZZZKEY_EQUAL;
    case sf::Key::Dash: return ZZZKEY_MINUS;
    case sf::Key::Space: return ZZZKEY_SPACE;
    case sf::Key::Return: return ZZZKEY_ENTER;
    case sf::Key::Back: return ZZZKEY_BACK;
    case sf::Key::Tab: return ZZZKEY_TAB;
    case sf::Key::PageUp: return ZZZKEY_PAGEUP;
    case sf::Key::PageDown: return ZZZKEY_PAGEDOWN;
    case sf::Key::End: return ZZZKEY_END;
    case sf::Key::Home: return ZZZKEY_HOME;
    case sf::Key::Insert: return ZZZKEY_INSERT;
    case sf::Key::Delete: return ZZZKEY_DELETE;
    case sf::Key::Add: return ZZZKEY_NUM_PLUS;
    case sf::Key::Subtract: return ZZZKEY_NUM_MINUS;
    case sf::Key::Multiply: return ZZZKEY_NUM_TIMES;
    case sf::Key::Divide: return ZZZKEY_NUM_DIVIDE;
    case sf::Key::Left: return ZZZKEY_LEFT;
    case sf::Key::Right: return ZZZKEY_RIGHT;
    case sf::Key::Up: return ZZZKEY_UP;
    case sf::Key::Down: return ZZZKEY_DOWN;
    case sf::Key::Numpad0: return ZZZKEY_NUM_0;
    case sf::Key::Numpad1: return ZZZKEY_NUM_1;
    case sf::Key::Numpad2: return ZZZKEY_NUM_2;
    case sf::Key::Numpad3: return ZZZKEY_NUM_3;
    case sf::Key::Numpad4: return ZZZKEY_NUM_4;
    case sf::Key::Numpad5: return ZZZKEY_NUM_5;
    case sf::Key::Numpad6: return ZZZKEY_NUM_6;
    case sf::Key::Numpad7: return ZZZKEY_NUM_7;
    case sf::Key::Numpad8: return ZZZKEY_NUM_8;
    case sf::Key::Numpad9: return ZZZKEY_NUM_9;
    case sf::Key::F1: return ZZZKEY_F1;
    case sf::Key::F2: return ZZZKEY_F2;
    case sf::Key::F3: return ZZZKEY_F3;
    case sf::Key::F4: return ZZZKEY_F4;
    case sf::Key::F5: return ZZZKEY_F5;
    case sf::Key::F6: return ZZZKEY_F6;
    case sf::Key::F7: return ZZZKEY_F7;
    case sf::Key::F8: return ZZZKEY_F8;
    case sf::Key::F9: return ZZZKEY_F9;
    case sf::Key::F10: return ZZZKEY_F10;
    case sf::Key::F11: return ZZZKEY_F11;
    case sf::Key::F12: return ZZZKEY_F12;
    case sf::Key::F13: return ZZZKEY_F13;
    case sf::Key::F14: return ZZZKEY_F14;
    case sf::Key::F15: return ZZZKEY_F15;
    case sf::Key::Pause: return ZZZKEY_PAUSE;
  }
  return ZZZKEY_NOKEY;
}

unsigned int SFMLContext::GetInputFlag()
{
  unsigned int flag=0;
  if (App_->GetInput().IsKeyDown(sf::Key::LControl)) SetBit(flag,ZZZFLAG_LCTRL);
  if (App_->GetInput().IsKeyDown(sf::Key::RControl)) SetBit(flag,ZZZFLAG_RCTRL);
  if (App_->GetInput().IsKeyDown(sf::Key::LAlt)) SetBit(flag,ZZZFLAG_LALT);
  if (App_->GetInput().IsKeyDown(sf::Key::RAlt)) SetBit(flag,ZZZFLAG_RALT);
  if (App_->GetInput().IsKeyDown(sf::Key::LShift)) SetBit(flag,ZZZFLAG_LSHIFT);
  if (App_->GetInput().IsKeyDown(sf::Key::RShift)) SetBit(flag,ZZZFLAG_RSHIFT);
  CompleteZZZFlags(flag);
  if (App_->GetInput().IsMouseButtonDown(sf::Mouse::Left)) SetBit(flag,ZZZFLAG_LMOUSE);
  if (App_->GetInput().IsMouseButtonDown(sf::Mouse::Right)) SetBit(flag,ZZZFLAG_RMOUSE);
  if (App_->GetInput().IsMouseButtonDown(sf::Mouse::Middle)) SetBit(flag,ZZZFLAG_MMOUSE);
  if (App_->GetInput().IsMouseButtonDown(sf::Mouse::XButton1)) SetBit(flag,ZZZFLAG_X1MOUSE);
  if (App_->GetInput().IsMouseButtonDown(sf::Mouse::XButton1)) SetBit(flag,ZZZFLAG_X2MOUSE);
  return flag;
}

}

#endif 